package htmlCanvas;

import context.*;

import util.Color;
import util.ContentType;
//import util.Jukebox;
import util.MediePlayer;
import java.io.*;
import java.util.Vector;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;


// ********************************************************************
// *** CLASS: HtmlCanvas
// ********************************************************************
public class HtmlCanvas extends Canvas implements Debug.Constants
{ //private static final boolean DEBUG=true; // Overriding Debug.Constants.DEBUG
  private static final Command homeCommand=new Command("Home",Command.EXIT,1);
  private static final Command pgUpCommand=new Command("PgUp",Command.SCREEN,2);
  private static final Command pgDnCommand=new Command("PgDn",Command.SCREEN,2);

//  private static final int backgroundColor=Color.white;
  private static final int backgroundColor=Color.yellow;
  private static final int foregroundColor=Color.black;
  private static final int hyperlinkColor=Color.red;
//  private static final int selectedlinkColor=Color.white;
  private static final int selectedlinkColor=Color.blue;

  private MIDlet midlet;
  private HtmlParser htmlParser;
  
  private int nPosX;
  private int nPosY;
    
  private int nScreenWidth;
  private int nScreenHeight;

  /** The currently selected hyperlink item. An index into items*/
  private int selectedHyperlink = -1;

  // Is there enough RAM on these devices to realistically
  // keep this info around?
//  private String lastURL = null;
//  private String lastPage = null;
//  private String currentPage = null;
  
  private Displayable homeScreen;
  private Display display;
  private HtmlPage currentPage=null;
  private class HtmlPage
  { private HtmlPage prevPage=null;
    private String content;
    private String url;
    public HtmlPage(String content,String url)
    { this.prevPage=currentPage;
      this.content=content;
      this.url=url;
      currentPage=this;
    }
    void open()
    { if(DEBUG) Debug.println("HtmlPage.open: content="+content);
      InputStream inputStream=new ByteArrayInputStream(content.getBytes());
      InputStreamReader reader=new InputStreamReader(inputStream);
	  htmlParser.parseXHTML(reader,url);
    
      selectedHyperlink = -1;
      // select the first hyperlink
      nextHyperlink(false);
      nPosY = 0;
      repaint();
    }
    void back()
    { if(prevPage!=null)
      { currentPage=prevPage;
        currentPage.open();
      }
      else if(homeScreen!=null)
      { display.setCurrent(homeScreen);
    	
      }
    }
    void home()
    { if(homeScreen!=null) display.setCurrent(homeScreen);
	  else if(prevPage!=null)
      { while(prevPage!=null) { currentPage=prevPage; prevPage=prevPage.prevPage; }
        currentPage.open();
      }
    	
    }
	  
  }
  
  

  // ******************************************************************
  // *** CONSTRUCTOR: HtmlCanvas
  // ******************************************************************
  public HtmlCanvas(MIDlet midlet)
  { this.midlet=midlet;
    this.display=Display.getDisplay(midlet);
	nScreenWidth = getWidth();
    nScreenHeight = getHeight();
   	htmlParser=new HtmlParser(nScreenWidth);
    nPosX = 0;
    nPosY = 0;
    addCommand(homeCommand);
    addCommand(pgUpCommand);
    addCommand(pgDnCommand);
    setCommandListener(new CommandListener()
    { public void commandAction(Command c,Displayable d)
      { if(c==homeCommand) currentPage.home();
        else if(c==pgUpCommand)
        {
          if(DEBUG) Debug.println("HtmlCanvas.CommandListener: PgUp -- Pressed");
          scroll(-nScreenHeight);
          repaint();
        }
        else if(c==pgDnCommand)
        {
          if(DEBUG) Debug.println("HtmlCanvas.CommandListener: PgDn -- Pressed");
          scroll(nScreenHeight);
          repaint();
        }
      }  
    });
  }

  // ******************************************************************
  // *** METHOD: show
  // ******************************************************************
  public void show()
  { this.homeScreen=display.getCurrent();
    display.setCurrent(this);
  }  

  // ******************************************************************
  // *** METHOD: openURL
  // ******************************************************************
  /**
  * Tell browser to load data from URL.
  * Valid protocols are "http://", "resource:///" 
  */
  public void openURL(final String url)
  { final String contentType=ContentType.get(url);
	if(DEBUG) Debug.println("HtmlCanvas.openURL: "+url+"  ContentType="+contentType);
	new Thread()
	{ public void run()
	  { try
	    { if(contentType.startsWith("image/"))
		  { currentPage=new HtmlPage("<IMG SRC=\""+url+"\"/>",url); }
//		  else if(contentType.startsWith("audio/"))
//		  {	Jukebox jukebox=new Jukebox();
//	    	InputStream stream=Util.getFileStream(url);
//	    	jukebox.play(stream,contentType);
//	    	//currentpage= ... m/ stop, og andre kontroller  // TODO:
//          }
		  else if( (contentType.startsWith("audio/")) || (contentType.startsWith("video/")) )
		  {	MediePlayer mediePlayer=new MediePlayer(midlet);
	    	InputStream stream=Util.getFileStream(url);
	    	mediePlayer.play(stream,contentType);
	    	//currentpage= ... m/ stop, og andre kontroller  // TODO:
          }
		  else currentPage=new HtmlPage(Util.getFile(url),url);
	    } catch(Exception e)
	    { //Debug.EXCEPTION("HtmlCanvas.openURL'run",e);
	      String error="<center><b>Requested file not available</b><br><br><b>URL:</b><br>"
            +url+"<br><br><b>EXCEPTION:</b><br>"+e+"</center>";
		  currentPage=new HtmlPage(error,url);
	    }
        currentPage.open();
	  }
	}.start();
  }

  // ******************************************************************
  // *** METHOD: openPage
  // ******************************************************************
  public void openPage(String page)
  { currentPage=new HtmlPage(page,"xxx://abracadabra");
    currentPage.open();
  }


  // ******************************************************************
  // *** METHOD: scroll
  // ******************************************************************
  public void scroll(int inc)
  { int maxPageHeight=htmlParser.getMaxPageHeight();
	nPosY += inc;
    if(nPosY>(maxPageHeight-nScreenHeight))
       nPosY=maxPageHeight-nScreenHeight;
    else if(nPosY<0) nPosY=0;
  }  
  
  // ******************************************************************
  // *** METHOD: nextHyperlink
  // ******************************************************************
  /**
  * Advance selected hyperlink to next link.
  * If it's not on this page, scroll display half page down.
  */
  private void nextHyperlink(boolean autoScroll)
  { int start=(selectedHyperlink>=0)?selectedHyperlink+1:0;
//    if(DEBUG) Debug.println("HtmlCanvas.nextHyperlink("+autoScroll+")");
    Vector items=htmlParser.getItems();
    for(int i=start;i<items.size();i++)
    { HtmlItem item=(HtmlItem)items.elementAt(i);
      if(item.isLink())
      { selectedHyperlink=i;
        if(autoScroll)
        { // if it's not on the screen scroll half page forward
          if(item.ypos>(nPosY+nScreenHeight)) scroll(nScreenHeight/2);
        }  
        return;
      }
    }
  }

  // ******************************************************************
  // *** METHOD: prevHyperlink
  // ******************************************************************
  /**
  * Backup to select the previous hyperlink HtmlItem.
  * If it's not on this page, scroll display half page back.
  */
  private void prevHyperlink()
  {
    Vector items=htmlParser.getItems();
	int start=(selectedHyperlink>=0)?selectedHyperlink-1:items.size()-1;
//    if(DEBUG) Debug.println("HtmlCanvas.prevHyperlink()");
    for(int i=start;i>=0;i--)
    { HtmlItem item=(HtmlItem)items.elementAt(i);
      if(item.isLink())
      { selectedHyperlink=i;
        // if it's not on screen, half page back
        if((item.ypos-(item.getHeight()+2))<nPosY) scroll(-nScreenHeight/2);
        return;
      }
    }
  }
  
  // ******************************************************************
  // *** METHOD: Canvas::paint
  // ******************************************************************
  /**
  * Redisplay the current page. Highlights any selected element which
  * is visible on the current page.
  */
  public void paint(Graphics g)
  { g.setColor(backgroundColor);
    g.fillRect(0,0,nScreenWidth,nScreenHeight);
    g.setColor(foregroundColor);
    // loop over the content items, displaying them
    Vector items=htmlParser.getItems();
    for(int i=0;i<items.size();i++)
    { HtmlItem item=(HtmlItem)items.elementAt(i);
      paint(item,g,selectedHyperlink==i);
    }
  }

  
  // ****************************************************************
  // *** METHOD: paint  -- VAR:   lokal til HtmlItem
  // ****************************************************************
  public void paint(HtmlItem item,Graphics g,boolean selected)
  {
    int anchor=Graphics.BOTTOM|Graphics.LEFT;
    if(item.isImage())
    { if(item.isLink())
      { if(selected)
        { // draw a border
//          if(DEBUG) Debug.println("   selectedHyperlink==i  Draw Image border");
          g.setColor(hyperlinkColor);
          g.fillRect(item.getXpos()-1,(item.getYpos()-nPosY-item.getHeight()-1)
                    ,item.getWidth()+2,item.getHeight()+2);
        }
      }
      g.drawImage(item.getImage(),item.getXpos(),(item.getYpos()-nPosY),anchor);
    }
    else
    { g.setFont(item.getFont());
      g.setColor(item.getColor());

      // Selected Hyperlink is shown in reverse video
      if(item.isLink())
      { if(selected)
        {
//          if(DEBUG) Debug.println("   selectedHyperlink==i  Draw Reverse Video");
          g.setColor(hyperlinkColor);
          g.fillRect(item.getXpos(),(item.getYpos()-nPosY)-item.getHeight()
        		  ,item.getWidth(),item.getHeight()+1);
          g.setColor(selectedlinkColor);
        }
        else g.setColor(hyperlinkColor);
      }
      g.drawString(item.getText(),item.getXpos(),item.getYpos()-nPosY,anchor);
    }
  }  
  



  // ******************************************************************
  // *** METHOD: fetchLink
  // ******************************************************************
  /**
  * Fetch an HTML document from a link URL.
  */
  private void fetchLink()
  {
    if(DEBUG) Debug.println("HtmlCanvas.fetchLink()");
//    lastPage = currentPage;
    String currentURL=htmlParser.getCurrentURL();
//    lastURL = currentURL;
    if(selectedHyperlink != -1)
    { String target=((HtmlItem)(htmlParser.getItems().elementAt(selectedHyperlink))).getLink();
      // If no ":", assume it's a relative link, (no protocol),
      // and append current page
      if(target.indexOf(':') == -1)
      { String currentURLBase = currentURL.substring(0,currentURL.lastIndexOf('/')+1);
        target = currentURLBase + target;
      }
      openURL(target);
    }
  }

  // ******************************************************************
  // *** METHOD: Canvas::keyPressed
  // ******************************************************************
  /**
  * Handle a keyboard input
  */
  protected void keyPressed(int keyCode)
  { int actCode=getGameAction(keyCode);
    if(DEBUG) Debug.println("HtmlCanvas.keyPressed("+keyCode+")"
                  +" -- KeyName="+getKeyName(keyCode)
                  +" -- GameAction="+actCode);
    
    if(actCode==0) switch(keyCode)
    { case KEY_NUM1: // scroll up
           if(DEBUG) Debug.println("KeyAction: 1 KEY_NUM1, code="+keyCode);
           scroll(-8);
           break;
      case KEY_NUM2: // home
           if(DEBUG) Debug.println("KeyAction: 2 KEY_NUM2, code="+keyCode);
           currentPage.home();
           break;
      case KEY_NUM3:// scroll down
           if(DEBUG) Debug.println("KeyAction: 3 KEY_NUM3, code="+keyCode);
           scroll(8);
           break;
    }
    else switch(actCode)
    { case FIRE: // select hyperlink
           if(DEBUG) Debug.println("GameAction: FIRE, code="+actCode);
           fetchLink();
           break;
      case LEFT: // back (select prev hyperlink)
           if(DEBUG) Debug.println("GameAction: LEFT, code="+actCode);
           currentPage.back();
           break;
      case UP:
           if(DEBUG) Debug.println("GameAction: UP, code="+actCode);
           prevHyperlink();
           break;
      case DOWN:
           if(DEBUG) Debug.println("GameAction: DOWN, code="+actCode);
           nextHyperlink(true);
           break;
    }
    repaint();
  }

  
}
